﻿//-----------------------------------------------------------------------
// <copyright file="Set.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Mark Phillips</author>
// <email>v-mphill@microsoft.com</email>
// <date>2004-05-24</date>
// <summary>provides a base class for all tasks that call to a Virtual Server COM component.</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.Registry
{
    using System;
    using System.Reflection;
    using System.Collections;
    using System.Runtime.InteropServices;
    using Microsoft.Sdc.Tasks;
    using Microsoft.Win32;
    using Microsoft.Build.Framework;

    /// <summary>
    /// 
    /// </summary>
    public class Set : TaskBase
    {
        private string value;
        private string key;
        private string data;
        private string machineName;
        private string registryHive;
        private bool changed;
        private string dataType = String.Empty;

        /// <summary>
        /// Returns TRUE if the reg key was set to a different value
        /// </summary>
        /// <value></value>
        [Output]
        public bool Changed
        {
            get
            {
                return changed;
            }

            set
            {
                changed = value;
            }
        }

        public string Data
        {
            get
            {
                return (data == null ? String.Empty : data);
            }

            set
            {
                data = value;
            }
        }

        public string DataType
        {
            get
            {
                return (dataType == null ? String.Empty : dataType);
            }
            set
            {
                dataType = value;
            }
        }

        [Required]
        public string RegistryHive
        {
            get
            {
                return (registryHive == null ? String.Empty : registryHive);
            }

            set
            {
                registryHive = value;
            }
        }

        /// <summary>
        /// Defaults to local machine if not specified.
        /// </summary>
        /// <value></value>
        public string MachineName
        {
            get
            {
                return (machineName == null ? String.Empty : machineName);
            }
            set
            {
                machineName = value;
            }
        }

        /// <summary>
        /// If not specified then the default for the key is returned.
        /// </summary>
        /// <value></value>
        public string Value
        {
            get
            {
                return (value == null ? String.Empty : value);
            }

            set
            {
                this.value = value;
            }
        }

        [Required]
        public string Key
        {
            get
            {
                return (key == null ? String.Empty : key);
            }

            set
            {
                key = value;
            }
        }

        /// <summary>
        /// </summary>
        public Set()
        {
        }


        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            this.changed = false;
            Microsoft.Win32.RegistryHive hive = (Microsoft.Win32.RegistryHive)Enum.Parse(typeof(Microsoft.Win32.RegistryHive), this.registryHive, true);

            RegistryKey registryKey = RegistryKey.OpenRemoteBaseKey(hive, this.MachineName);

            RegistryKey subKey = registryKey.OpenSubKey(this.Key, true);
            object oldData = subKey.GetValue(this.Value);
            if (oldData == null || oldData.ToString() != this.Data)
            {
                if (this.DataType == String.Empty)
                {
                    subKey.SetValue(this.Value, this.Data);
                }
                else
                {
                    // gilesk Dec 05. Added handling of specific types. Note assumption that ',' is separator
                    // for binary and multistring value types.
                    char[] separator = {','};
                    object registryValue = null;

                    Microsoft.Win32.RegistryValueKind valueKind = (Microsoft.Win32.RegistryValueKind)Enum.Parse(typeof(Microsoft.Win32.RegistryValueKind), this.dataType, true);
                    switch (valueKind)
                    {
                        case RegistryValueKind.Binary :
                            string[] parts = this.Data.Split(separator);
                            byte[] value = new byte[parts.Length];
                            for (int i = 0; i < parts.Length; value[i++] = Byte.Parse(parts[i]));
                            registryValue = value;
                            break;

                        case RegistryValueKind.DWord :
                            registryValue = uint.Parse(this.Data);
                            break;

                        case RegistryValueKind.MultiString :
                            parts = this.Data.Split(separator);
                            registryValue = parts;
                            break;

                        case RegistryValueKind.QWord:
                            registryValue = ulong.Parse(this.Data);
                            break;

                        default :
                            registryValue = this.Data;
                            break;
                    }
                    subKey.SetValue(this.value, registryValue, valueKind);
                }
                changed = true;
            }
            if (changed)
            {
                // Broadcast that there has been a config change
                int result = NativeMethods.SendMessageTimeout(
                    NativeMethods.HWND_BROADCAST,
                    NativeMethods.WM_SETTINGCHANGE,
                    0,
                    "Environment",
                    NativeMethods.SMTO_ABORTIFHUNG,
                    0,
                    0);
            }
            subKey.Close();
            registryKey.Close();
        }
    }
}
